"""

用于快速调整Cube 工程中Core/User 部分的用户代码文件的结构，
修改一部分源码内容，从而能够适配我习惯的工程结构。

脚本文件必须放在工程根目录下，Cube 工程的Src 和Inc 也要粘贴到根目录。

"""

import os
from pathlib import Path
from typing import Optional
from send2trash import send2trash
import re


here = Path(__file__).parent
# 创建或调整源码文件夹 src/
src_folder = here / "src"
inc_folder = (here / "Inc").resolve()

do_move_header_to_src = True
# 如果存在小写的inc 文件夹，则其中的头文件不会被移动到src
if inc_folder.name == "inc":
    do_move_header_to_src = False


# 找出头文件的位置，同时将Inc 内的头文件移动到src
def inc_header_process(header_in_src, header_in_inc) -> Path:
    if header_in_inc.exists():
        if header_in_src.exists():
            print(f"Notice: old [ {header_in_src.name} ] will be sent to trash")
            send2trash(header_in_src)
        if do_move_header_to_src:
            header_in_inc.rename(header_in_src)
            return header_in_src
        else:
            return header_in_inc
    else:
        return header_in_src


# 循环只运行一次，用来方便goto 到程序退出点
for i in (1,):
    if not src_folder.exists():
        print("SRC Not Found.")
        break

    # src 文件夹必须是小写的src，不是的话就rename
    real_src = src_folder.resolve()
    if real_src.name != "src":
        src_folder = real_src.rename(here / "src")

    # 处理src 内的cube 源文件的文件名
    # main.c
    main_c = src_folder / "main.c"
    hal_main_c = src_folder / "hal_main.c"
    if main_c.exists():
        if hal_main_c.exists():
            # 已经存在的cube 文件会被删除到回收站
            print("Notice: old [ hal_main.c ] will be sent to trash")
            send2trash(hal_main_c)
        main_c.rename(hal_main_c)

    # main.h
    main_h = src_folder / "main.h"
    inc_main_h = inc_folder / "main.h"
    main_h = inc_header_process(main_h, inc_main_h)
    if main_h is None:
        break
    hal_main_h = main_h.parent / "hal_main.h"
    if main_h.exists():
        if hal_main_h.exists():
            # 已经存在的cube 文件会被删除到回收站
            print("Notice: old [ hal_main.h ] will be sent to trash")
            send2trash(hal_main_h)
        main_h.rename(hal_main_h)

    # 查找其他源文件
    # 器件名称不确定，所以要先根据文件名确定器件名

    l = list(src_folder.glob("system_*.c"))
    if len(l) == 1:
        system_c = l[0]
    elif len(l) > 1:
        print("More than one system_*.c file")
        break
    else:
        # src 文件夹下必须有system 文件夹，
        # 不然后续处理很麻烦
        print("No system_*.c file under src")
        break

    device_name = system_c.stem.removeprefix("system_")
    if len(device_name) < 5:
        print(f"Device name too short: {device_name}")

    it_c = src_folder / f"{device_name}_it.c"
    msp_c = src_folder / f"{device_name}_hal_msp.c"

    conf_h = src_folder / f"{device_name}_hal_conf.h"
    inc_conf_h = inc_folder / f"{device_name}_hal_conf.h"
    it_h = src_folder / f"{device_name}_it.h"
    inc_it_h = inc_folder / f"{device_name}_it.h"

    conf_h = inc_header_process(conf_h, inc_conf_h)
    if conf_h is None:
        break

    # 删掉没用的头文件
    if it_h.exists():
        os.remove(it_h)

    if inc_it_h.exists():
        os.remove(inc_it_h)

    # 开始依次修改文件内容

    # hal_main.c
    # 修改头文件，更改main 函数名为hal_main，避免和自己定义的main 冲突
    # 删掉hal_main 函数里的死循环，可以用自己的代码调用hal_main 完成初始化
    if hal_main_c.exists():
        text = hal_main_c.read_text()
        text = text.replace('#include "main.h"', '#include "hal_main.h"')
        text = text.replace("int main(void)", "int hal_main(void)")

        # 查找main 函数的范围
        main_start_index = text.find("int hal_main(void)")
        # 在main 之后找到一个位于行首的右花括号，如果代码缩进格式没错，
        # 这就是main 函数结束的位置
        m = re.search(r"^}$", text[main_start_index:], flags=re.MULTILINE)

        if m is None:
            print('Failed to locate the "}" of main function')
            break

        end_bracket_index = main_start_index + m.end()

        tail_half = text[end_bracket_index - 1 :]
        # 给hal_main 加上return 0，去掉编译警告
        tail_half = tail_half.replace("}", "  return 0;\n}", 1)

        front_half = text[: end_bracket_index - 1]

        # 去掉最靠近main 函数尾部的一个while 死循环
        while_index = front_half.rfind("while (1)")
        middle_section = front_half[while_index:].replace("while (1)", "while (0)", 1)
        text = front_half[:while_index] + middle_section + tail_half

        # 去掉函数的static 标记，方便从其他地方使用
        m = re.subn(r'^static ', '', text, flags=re.MULTILINE)
        if m[1] > 0:
            text = m[0]

        hal_main_c.write_text(text)

    # hal_main.h
    if hal_main_h.exists():
        # 直接把main.h 所有的内容替换掉
        hal_main_h_text = "#pragma once\n\n" '#include "stm32f1xx_hal.h"\n\n' "void Error_Handler(void);\n"
        hal_main_h.write_text(hal_main_h_text)

    # xxxx_it.c
    if it_c.exists():
        text = it_c.read_text()
        text = text.replace('#include "main.h"', '#include "hal_main.h"')
        text = text.replace('#include "stm32f1xx_it.h"', '')
        it_c.write_text(text)

    # xxxx_hal_msp.c
    if msp_c.exists():
        text = msp_c.read_text()
        text = text.replace('#include "main.h"', '#include "hal_main.h"')
        msp_c.write_text(text)

    # 如果要从inc 挪走头文件，之后就把inc 删掉
    if do_move_header_to_src and inc_folder.exists():
        try:
            os.rmdir(inc_folder)
        except:
            print('Failed to delete Inc folder.')

# 退出点:
input("Complete ...")
